using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using System.Threading;
using static System.Runtime.InteropServices.JavaScript.JSType;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;

namespace PhoneCrawler
{
    public partial class Form1 : Form
    {
        private HttpClient _client = new HttpClient();
        private ConcurrentDictionary<string, HashSet<string>> _phoneNumbers = new ConcurrentDictionary<string, HashSet<string>>();
        private HashSet<string> _globalPhoneNumbers = new HashSet<string>(); // 用于存储所有电话号码以避免全局重复
        private SemaphoreSlim _semaphore = new SemaphoreSlim(20); // 限制最大并发数为20
        private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
        // 用于控制弹窗只触发一次
        private bool _isCrawlCompleteNotified = false;

        private int _maxDepth = 3;

        public Form1()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            string keyword = textBox1.Text;
            await SearchPhoneNumbers("https://www.bing.com/search?q=" + keyword, 0, _cancellationTokenSource.Token);
        }

        private async Task SearchPhoneNumbers(string url, int depth, CancellationToken token)
        {
            if (depth > _maxDepth || _phoneNumbers.Values.Sum(x => x.Count) >= 100 || token.IsCancellationRequested)
                return;

            string html;
            try
            {
                html = await _client.GetStringAsync(url).ConfigureAwait(false);
            }
            catch (HttpRequestException)
            {
                return;  // 网络错误，跳过这个URL
            }

            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(html);

            var nodeCollection = doc.DocumentNode.SelectNodes("//a[@href]");
            if (nodeCollection == null)
                return;

            List<Task> tasks = new List<Task>();
            Uri baseUri = new Uri(url);

            foreach (var link in nodeCollection)
            {
                string hrefValue = link.GetAttributeValue("href", string.Empty);
                Uri fullUri = new Uri(baseUri, hrefValue);
               
                if (fullUri.ToString().StartsWith("http") && _phoneNumbers.Count < 100 && !token.IsCancellationRequested)
                {
                    tasks.Add(Task.Run(async () => {
                        await ExtractPhoneNumbers(fullUri.ToString()).ConfigureAwait(false);
                    }, token));
                    tasks.Add(SearchPhoneNumbers(fullUri.ToString(), depth + 1, token));
                }
            }

            await Task.WhenAll(tasks).ConfigureAwait(false);
        }


        private async Task ExtractPhoneNumbers(string pageUrl)
        {
            string pageContent;
            try
            {
                pageContent = await _client.GetStringAsync(pageUrl).ConfigureAwait(false);
            }
            catch (HttpRequestException)
            {
                return;  // 网络错误，跳过这个URL
            }

            var matches = Regex.Matches(pageContent, @"(\d{3,4}-\d{7,8}|1[3-9]\d{9})");
            foreach (Match match in matches)
            {
                if (_cancellationTokenSource.IsCancellationRequested)
                {
                    return;
                }
                bool isNewNumber;
                lock (_globalPhoneNumbers)
                {
                    isNewNumber = _globalPhoneNumbers.Add(match.Value);
                }

                if (isNewNumber)
                {
                    var numberSet = _phoneNumbers.GetOrAdd(pageUrl, new HashSet<string>());
                    if (numberSet.Add(match.Value))
                    {
                        Invoke(new Action(() =>
                        {
                            listBox1.Items.Add($"{match.Value} - {pageUrl}");
                            UpdatePhoneNumberCount();
                        }));
                    }
                }
            }
        }

        private void UpdatePhoneNumberCount()
        {
            label3.Text = _globalPhoneNumbers.Count.ToString();
            if (_globalPhoneNumbers.Count >= 100 && !_isCrawlCompleteNotified)
            {
                _isCrawlCompleteNotified = true;
                _cancellationTokenSource.Cancel();
                MessageBox.Show("已爬取 100 个手机号", "爬取结束", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

    }
}
